﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TosObserver;
using System.Diagnostics;
using MaasOne.Finance;
using MaasOne.RSS;
using tdaactx;

namespace Tos2Google
{
    public abstract class Signal
    {
        public string Symbol;
        public abstract string ToString();
    }

    public class BuySignal : Signal 
    {
        public override string ToString()
        {
            return "BUY " + Symbol;
        }
    }

    public class SellSignal : Signal 
    {
        public override string ToString()
        {
            return "SELL " + Symbol;
        }
    }

    public class DecisionEngine
    {
        internal static Signal ProcessTickData(TickData tickData)
        {
            // no need to worry about parallelism (degree 1 has been requested == no parallelism)
            DecisionEngine de = EngineBySymbol(tickData.Symbol.ToUpper());
            return de.ProcessTickData(tickData.Topic, tickData.Value, tickData.Backfill);
        }

        public static DecisionEngine EngineBySymbol(string sym)
        {
            DecisionEngine de = null;
            if (EnginesPerSymbol.ContainsKey(sym))
                de = EnginesPerSymbol[sym];
            else
            {
                de = new DecisionEngine(sym);
                EnginesPerSymbol.Add(sym, de);
            }
            return de;
        }

        internal static Dictionary<string, DecisionEngine> EnginesPerSymbol = new Dictionary<string, DecisionEngine>();
        internal HistQuotesDataChain Historicals = null;
        internal Feed News = null;
        internal List<Bar> Bars10min = null;
        internal List<Bar> Bars1min = null;

        public readonly string Symbol;

        private DecisionEngine(string symbol)
        {
            Symbol = symbol;
        }

        static DateTime january1970 = new DateTime(1970, 1, 1); // from help: QuoteDate == days since 1/1/1970

        private void LoadBackfill(TDABackfillData backfill)
        {
            var result = new List<Bar>();
            var barCount = backfill.count;
            for (var barIndex = 0; barIndex < barCount; barIndex++)
            {
                var bar = new Bar
                {
                    Sequence = backfill.Sequence[barIndex],
                    Close = (float)backfill.Close[barIndex],
                    High = (float)backfill.High[barIndex],
                    Low = (float)backfill.Low[barIndex],
                    Open = (float)backfill.Open[barIndex],
                    Volume = backfill.Volume[barIndex],

                    // calculated ones
                    // using january1970: from help: Backfill Data "Date" == # of days since 1/1/1970
                    StartTime = january1970.AddDays(backfill.Date[barIndex]).AddSeconds(backfill.Time[barIndex]), // from help: Backfill Data "Time" == # of seconds since midnight
                    // if we were using Sequence, then it would be: StartTime = dateBaseTimAddDays(backfill.Date[barIndex]).AddHours(8).AddMinutes(backfill.Sequence[barIndex]),
                };
                if (bar.Open == 0 || bar.High == 0 || bar.Low == 0 || bar.Close == 0)
                    continue; // for some reason it gives sometimes such zero-bars (all zeros actually)
                result.Add(bar);
            }
            result.Reverse(); // let's reverse, better to handle later

            int minute_bar_count = 0;
            int tenMinute_bar_count = 0;
            DateTime? last = null;
            int index = 0;
            foreach (var bar in result)
            {
                index++;
                if (!last.HasValue)
                    last = bar.StartTime;
                else
                {
                    TimeSpan diff = last.Value - bar.StartTime;
                    if (diff.TotalSeconds == 60)
                        minute_bar_count++;
                    else if (diff.TotalSeconds == 600)
                        tenMinute_bar_count++;
                    last = bar.StartTime;
                }
            }
            if (minute_bar_count == 0 && tenMinute_bar_count == 0)
                return; // couldn't tell (hopefully never happens)
            if (minute_bar_count > tenMinute_bar_count)
            {
                Bars1min = result;
                //Debug.WriteLine("Bars1min");
            }
            else
            {
                Bars10min = result;
                //Debug.WriteLine("Bars10min");
            }
        }

        private FullData Data = new FullData();

        private Signal ProcessTickData(TOSTopic tosTopic, decimal value, TDABackfillData backfill)
        {
            if (backfill == null)
                Data.Fill(tosTopic, value);
            else
                LoadBackfill(backfill);

            if (!Data.AllFilled || Bars10min == null || Bars1min == null)
                return null; // must wait for all to be there
            var signal = Decision.Make(Data, Historicals, News, Bars10min, Bars1min);
            if (signal == null)
                return null;
            signal.Symbol = Symbol;
            return signal;
        }
    }
}
